﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using Interface;
using Interface.Api;
using yafc.SessionLayer;
using System.ComponentModel;

namespace yafc
{
    public partial class Mainframe : Form
	{
		#region Fields

		static public Dictionary<string, IPlugin> Plugins = new Dictionary<string, IPlugin>();

		private Session session = new Session();

		private ManualResetEvent signalExit = new ManualResetEvent(false);
		private UpdateThread updateThread;

		#endregion

		#region Constructor
		public Mainframe()
        {
            InitializeComponent();

			UpdateThread.Callback callback = () => this.Invoke((MethodInvoker)updateTL);
			updateThread = new UpdateThread(session, callback, signalExit);

			Closing += cleanUp;
        }
		#endregion

		#region Public Methods

		public void updateNewTL(Post[] Posts)
		{
			foreach (Post p in Posts)
			{
				//timeline.Items.Insert(0, )
			}
		}

		public void updateTL()
		{
			IEnumerable<Post> posts;

			posts = session.NewPosts;
			foreach (Post p in posts)
			{
				addPost(p);
			}
		}

		#endregion

		#region Private Methods

		#region Plugin

		private string PluginInfo
		{
			get
			{
				string info = "Plugins:" + Environment.NewLine;
				foreach (KeyValuePair<string, IPlugin> pair in Plugins)
				{
					IPlugin p = pair.Value;
					info += Environment.NewLine + p.Name + ": " + p.Desc;
				}
				return info;
			}
		}

		private void checkPlugins(string Path)
		{
			string[] paths = Directory.GetFiles(Path, "*.dll");
			foreach (string path in paths)
			{
				if (path.Substring(path.LastIndexOf(".")) == ".dll")
				{
					try
					{
						string file = path.Substring(path.LastIndexOf("\\") + 1);
						Assembly asm = Assembly.LoadFile(path);
						Type[] types = asm.GetTypes();

						foreach (Type type in types)
						{
							if (!type.IsInterface
								&& type.GetInterface("Interface.IPlugin", true) == typeof(Interface.IPlugin))
							{
								IPlugin plugin = (IPlugin)asm.CreateInstance(type.FullName);
								Plugins.Add(plugin.Name, plugin);
							}
						}
					}
					catch (System.Exception ex)
					{
						MessageBox.Show(ex.Message, "Load Plugin Failed", MessageBoxButtons.OK);
					}
				}
			}
		}

		private void buildPluginsMenu()
		{
			foreach(KeyValuePair<string, IPlugin> p in Plugins)
			{
				ToolStripMenuItem item = new ToolStripMenuItem(p.Key);
				item.Click += onMenuClick;
				serviceToolStripMenuItem.DropDownItems.Add(item);
			}
		}

		#endregion 
		
		private void mainframe_Load(object sender, EventArgs e)
		{
			checkPlugins(Application.StartupPath);
			buildPluginsMenu();

			session.Activated = true;

			Thread thread = new Thread(updateThread.run);
			thread.Start();
		}

		private void onMenuClick(object sender, EventArgs e)
		{
			ToolStripItem item = (ToolStripItem)sender;

			Login loginDialog = new Login(session);
			loginDialog.ShowDialog(item.Text);
		}

		private void send_Click(object sender, EventArgs e)
		{
			if (input.Text.Length == 0)
				return;

			try
			{
				updateThread.post(input.Text);
				input.Text = null;
			}
			catch (System.Exception ex)
			{
				throw ex;
			}
		}

		private void addPost(Post P)
		{
			const int MAX_LINE = 30;
			string message = P.name + ": " + P.message + " - " + P.dateTime.ToString();
			if (message.Length <= MAX_LINE)
			{
				timeline.Items.Insert(0, message);
			}
			else
			{
				int i = 0;
				int p = 0;
				int n = message.Length;
				while (p < message.Length)
				{
					timeline.Items.Insert(i++, message.Substring(p, Math.Min(n, MAX_LINE)));
					p += MAX_LINE;
					n -= MAX_LINE;
				}
			}
			timeline.Items.Insert(0, "");
		}

		private void helpMenuItemAbout_Click(object sender, EventArgs e)
		{
			About about = new About();
			about.Description += PluginInfo;
			about.ShowDialog();
		}

		private void helpMenuItemHelp_Click(object sender, EventArgs e)
		{
			HelpInfo helpInfo = new HelpInfo();
			helpInfo.ShowDialog();
		}

		private void cleanUp(object sender, CancelEventArgs e)
		{
			signalExit.Set();
			while (!updateThread.SignalExited.WaitOne(100))
			{
				Application.DoEvents();
			}
		}

		private void input_Enter(object sender, EventArgs e)
		{
			if (input.Text.Length > 0)
			{
				input.SelectAll();
			}
		}

		#endregion
	}
}
